package mirrormonkey.util.annotations.parsing;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;

/**
 * Abstract class that will be used to collect <tt>Members</tt>.
 * 
 * @author Philipp Christian Loewner
 * 
 */
public abstract class MemberIR extends AnnotationIR {

	/**
	 * Creates a new <tt>MemberDataIR</tt> for an element. This constructor should
	 * be called by subclasses if this <tt>MemberDataIR</tt> is the first IR created
	 * for the element.
	 * 
	 * @param parser
	 *            the <tt>AnnotationParser</tt> that parses the class hierarchy
	 * @param element
	 *            the <tt>Member</tt> that this <tt>MemberDataIR</tt> is created for
	 */
	public MemberIR(AnnotationParser parser, AnnotatedElement element) {
		super(parser, element);
	}

	/**
	 * Creates a new <tt>MemberDataIR</tt> and copies data from a previous
	 * <tt>MemberDataIR</tt>. This constructor should be called by subclasses if
	 * this <tt>MemberDataIR</tt> replaces another IR.
	 * 
	 * @param previous
	 *            the previous <tt>MemberDataIR</tt> that matched <tt>element</tt>
	 * @param element
	 *            the <tt>Member</tt> that this <tt>MemberDataIR</tt> is created for
	 */
	public MemberIR(MemberIR previous, AnnotatedElement element) {
		super(previous, element);
	}

	/**
	 * Returns <tt>true</tt>, if this <tt>MemberDataIR</tt> requires all membersById of
	 * the current class to be parsed a second time. Inheriting classes could,
	 * for example, return <tt>true</tt> here if they collect other membersById than
	 * just the one they were created for.
	 * 
	 * @return <tt>true</tt>, if all membersById of the current class should be
	 *         parsed a second time, <tt>false</tt> otherwise
	 */
	public boolean requireReparse() {
		return false;
	}

	@Override
	public String toString() {
		return getClass() + ":" + "\n  collectedAnnotations: "
				+ collectedAnnotations;
	}

	/**
	 * Returns <tt>true</tt> if this <tt>MemberDataIR</tt> matches <tt>member</tt>.
	 * A <tt>MemberDataIR</tt> matches a <tt>Member</tt> exactly if it will collect
	 * the member and / or its annotations.<br>
	 * 
	 * For every <tt>Member</tt>, only the first matching <tt>MemberDataIR</tt> will
	 * be allowed to parse it (or a new one will be created to parse it if no
	 * current IR is found). Thus, users should guarantee that there is only one
	 * IR at any point of time that will match a specific <tt>Member</tt>.
	 * 
	 * @param member
	 *            the <tt>Member</tt> that could be parsed by this
	 *            <tt>MemberDataIR</tt> if the IR matches
	 * @return <tt>true</tt>, if this <tt>MemberDataIR</tt> matches <tt>member</tt>
	 *         and wants its <tt>parseField</tt> or <tt>parseMethod</tt> method
	 *         to be called.
	 */
	public abstract boolean matches(Member member);

	/**
	 * Collects a field and / or its annotations. This method is only called by
	 * the framework if <tt>field</tt> matches this <tt>MemberDataIR</tt>.
	 * 
	 * @param field
	 *            <tt>Field</tt> that should be parsed
	 */
	public abstract void parseField(Field field);

	/**
	 * Collects a method and / or its annotations. This method is only called by
	 * the framework if <tt>method</tt> matches this <tt>MemberDataIR</tt>.
	 * 
	 * @param method
	 *            <tt>Method</tt> that should be parsed
	 */
	public abstract void parseMethod(Method method);

	/**
	 * Collects a constructor and / or its annotations. This method is only
	 * called by the framework if <tt>method</tt> matches this <tt>MemberDataIR</tt>
	 * .
	 * 
	 * @param constr
	 *            <tt>Constructor</tt> that should be parsed
	 */
	public abstract void parseConstructor(Constructor<?> constr);

	/**
	 * Moved up the hierarchy from <tt>ConstructorIR</tt> so look there for
	 * documentation
	 * 
	 * @param clazz
	 *            last class in the hierarchy
	 * @return <tt>true</tt>, if this <tt>MemberDataIR</tt> should be kept,
	 *         <tt>false</tt> otherwise
	 */
	public boolean isValidFor(@SuppressWarnings("unused") Class<?> clazz) {
		return true;
	}

	/**
	 * Returns an array of classes extending <tt>Member</tt> for which this
	 * <tt>MemberDataIR</tt> should be registered.
	 * 
	 * @return <tt>Class<? extends MemberDataIR>[]</tt> to register this
	 *         <tt>MemberDataIR</tt> for. This class determines for which
	 *         <tt>Members</tt> the <tt>matches</tt> method is called to even
	 *         determine if this <tt>MemberDataIR</tt> will collect the member.
	 */
	public abstract Class<?>[] getListenMemberClasses();

}
